/**
 *  @file
 *  @brief   和数据库交互，进行数据转换
 *  @author  wanghuan
 *  @date    2024.09.13
 *  @version  v1.0
 *  @par Copyright(c):  ShenGong  Simulation corporation
 */
#pragma once
#include <vector>

#include "Utility/Algebra/Matrix.h"

#include "DataStructure/Common/Out.h"
#include "DataStructure/Common/Real.h"
#include "DataStructure/Input/Solver/DOFDirections.h"
#include "DataStructure/Result/Nodal/DISPLACEMENTData.h"
#include "DataStructure/Result/Nodal/EIGENVECTORData.h"
#include "DataStructure/Result/Nodal/TEMPERATUREData.h"

#include "DBManager/IService/Input/Node/INodeService.h"

#include "SGFem/Pre/Assembly/Assembly.h"
#include "SGFem/Pre/Common/PreExport.h"

/** @brief 数据适配器
 *
 * 本类包含一些列静态函数，用于进行数据打包以适应数据层存储；或者从数据层获取数据转换成 业务层需要的格式
 */
SG_NAMESPACE_OPEN
namespace FEMSolver
{
    static const ::SG::DataStructure::FEM::DofSet DOFS{
        SG::DataStructure::FEM::DOFDirections::DOF_Ux,   SG::DataStructure::FEM::DOFDirections::DOF_Uy,
        SG::DataStructure::FEM::DOFDirections::DOF_Uz,   SG::DataStructure::FEM::DOFDirections::DOF_Rotx,
        SG::DataStructure::FEM::DOFDirections::DOF_Roty, SG::DataStructure::FEM::DOFDirections::DOF_Rotz
    };

    class Pre_DECLSPEC DataAdapter
    {
      public:
        /**
         * @brief   : 将矩阵数据打包转换成Nastran的数据结构
         *  该函数只适用于 与`DISPLACEMENTData`类结构一致的数据  id/x/y/z/rx/ry/rz/domainId
         * @param   : M 矩阵数据
         * @param   : nastranData
         * @author  : wxc
         * @date    : 2024.11.19
         */
        template <typename T>
        static void PackGridField (const std::vector<SG::DataStructure::Common::Real>& M, std::vector<T>& _OUT nastranData)
        {
            nastranData.clear ();

            auto&       assembly = AssemblyEigen::GetInstance ();
            const auto& nodeIds  = assembly.GetNodeIds ();

            std::vector<int> dofGlobalIds (6);
            for (const auto& nodeId : nodeIds)
            {
                assembly.ComputeGlobalDOFId (nodeId, SG::FEMSolver::DOFS, dofGlobalIds);

                T obj;
                obj.m_id = nodeId;  // 节点ID

                // 获取结果
                obj.m_X  = (dofGlobalIds[0] < 0) ? 0.0 : M[dofGlobalIds[0]];
                obj.m_Y  = (dofGlobalIds[1] < 0) ? 0.0 : M[dofGlobalIds[1]];
                obj.m_Z  = (dofGlobalIds[2] < 0) ? 0.0 : M[dofGlobalIds[2]];
                obj.m_RX = (dofGlobalIds[3] < 0) ? 0.0 : M[dofGlobalIds[3]];
                obj.m_RY = (dofGlobalIds[4] < 0) ? 0.0 : M[dofGlobalIds[4]];
                obj.m_RZ = (dofGlobalIds[5] < 0) ? 0.0 : M[dofGlobalIds[5]];

                nastranData.push_back (obj);
            }
        }

        /**
         * @brief    将温度数据打包转换成Nastran的数据结构
         *
         * @param    M
         * @param    nastranData
         * @author   wxc
         * @date     2025.01.09
         */
        static void PackGridTemperature (const std::vector<SG::DataStructure::Common::Real>&         M,
                                         std::vector<SG::DataStructure::Post::TEMPERATUREData>& _OUT nastranData)
        {
            nastranData.clear ();

            auto&       assembly = AssemblyEigen::GetInstance ();
            const auto& nodeIds  = assembly.GetNodeIds ();

            std::vector<int> dofGlobalIds (1);
            for (const auto& nodeId : nodeIds)
            {
                assembly.ComputeGlobalDOFId (nodeId, { SG::DataStructure::FEM::DOFDirections::DOF_Ux }, dofGlobalIds);

                SG::DataStructure::Post::TEMPERATUREData obj;
                obj.m_id = nodeId;  // 节点ID

                // 获取结果
                obj.m_VALUE = (dofGlobalIds[0] < 0) ? 0.0 : M[dofGlobalIds[0]];

                nastranData.push_back (obj);
            }
        }

        /**
         * @brief   : 将Nastran的数据结构 转换为 矩阵数据
         *  该函数只适用于 与`DISPLACEMENTData`类结构一致的数据 id/x/y/z/rx/ry/rz/domainId
         * @tparam T
         * @param   : nastranData
         * @param   : M
         * @author  : wxc
         * @date    : 2024.11.19
         */
        template <typename T>
        static void UnpackGridField (const std::vector<T>& nastranData, std::vector<SG::DataStructure::Common::Real>& _OUT M)
        {
            auto&      assembly  = AssemblyEigen::GetInstance ();
            const auto nTotalDof = assembly.GetTotalDOFSize ();

            M.resize (nTotalDof, 0.0);

            std::vector<int> nodeGlobalDofIds (6);

            for (const auto& nodeData : nastranData)
            {
                assembly.ComputeGlobalDOFId (nodeData.m_id, DOFS, _OUT nodeGlobalDofIds);
                if (nodeGlobalDofIds[0] > -1)
                {
                    M[nodeGlobalDofIds[0]] = nodeData.m_X;
                }
                if (nodeGlobalDofIds[1] > -1)
                {
                    M[nodeGlobalDofIds[1]] = nodeData.m_Y;
                }
                if (nodeGlobalDofIds[2] > -1)
                {
                    M[nodeGlobalDofIds[2]] = nodeData.m_Z;
                }
                if (nodeGlobalDofIds[3] > -1)
                {
                    M[nodeGlobalDofIds[3]] = nodeData.m_RX;
                }
                if (nodeGlobalDofIds[4] > -1)
                {
                    M[nodeGlobalDofIds[4]] = nodeData.m_RY;
                }
                if (nodeGlobalDofIds[5] > -1)
                {
                    M[nodeGlobalDofIds[5]] = nodeData.m_RZ;
                }
            }
        }

        /**
         * @brief   : 转换复数矩阵数据
         *  该函数只适用于 与`DISPLACEMENT_CPLXData`类结构一致的数据
         * @author  : wxc
         * @date    : 2024.11.29
         */
        template <typename T>
        static void PackGridFieldCplx (const std::vector<std::complex<double>>& M, std::vector<T>& _OUT nastranData)
        {
            nastranData.clear ();

            auto&       assembly = AssemblyEigen::GetInstance ();
            const auto& nodeIds  = assembly.GetNodeIds ();

            std::vector<int> dofGlobalIds (6);
            for (const auto& nodeId : nodeIds)
            {
                assembly.ComputeGlobalDOFId (nodeId, DOFS, dofGlobalIds);

                T obj;
                obj.m_id = nodeId;  // 节点ID

                // 获取结果
                obj.m_XR  = (dofGlobalIds[0] < 0) ? 0.0 : M[dofGlobalIds[0]].real ();
                obj.m_YR  = (dofGlobalIds[1] < 0) ? 0.0 : M[dofGlobalIds[1]].real ();
                obj.m_ZR  = (dofGlobalIds[2] < 0) ? 0.0 : M[dofGlobalIds[2]].real ();
                obj.m_RXR = (dofGlobalIds[3] < 0) ? 0.0 : M[dofGlobalIds[3]].real ();
                obj.m_RYR = (dofGlobalIds[4] < 0) ? 0.0 : M[dofGlobalIds[4]].real ();
                obj.m_RZR = (dofGlobalIds[5] < 0) ? 0.0 : M[dofGlobalIds[5]].real ();
                // 获取结果
                obj.m_XI  = (dofGlobalIds[0] < 0) ? 0.0 : M[dofGlobalIds[0]].imag ();
                obj.m_YI  = (dofGlobalIds[1] < 0) ? 0.0 : M[dofGlobalIds[1]].imag ();
                obj.m_ZI  = (dofGlobalIds[2] < 0) ? 0.0 : M[dofGlobalIds[2]].imag ();
                obj.m_RXI = (dofGlobalIds[3] < 0) ? 0.0 : M[dofGlobalIds[3]].imag ();
                obj.m_RYI = (dofGlobalIds[4] < 0) ? 0.0 : M[dofGlobalIds[4]].imag ();
                obj.m_RZI = (dofGlobalIds[5] < 0) ? 0.0 : M[dofGlobalIds[5]].imag ();

                nastranData.push_back (obj);
            }
        }

        /**
         * @brief   : 将Nastran的数据结构 转换为 复数矩阵数据
         *  该函数只适用于 与`DISPLACEMENT_CPLXData`类结构一致的数据
         * @author  : wxc
         * @date    : 2024.11.29
         */
        template <typename T>
        static void UnpackGridFieldCplx (const std::vector<T>& nastranData, std::vector<std::complex<double>>& _OUT M)
        {
            auto&      assembly  = AssemblyEigen::GetInstance ();
            const auto nTotalDof = assembly.GetTotalDOFSize ();

            M.resize (nTotalDof, 0.0);

            std::vector<int> nodeGlobalDofIds (6);

            for (const auto& nodeData : nastranData)
            {
                assembly.ComputeGlobalDOFId (nodeData.m_id, DOFS, _OUT nodeGlobalDofIds);
                if (nodeGlobalDofIds[0] > -1)
                {
                    M[nodeGlobalDofIds[0]] = { nodeData.m_XR, nodeData.m_XI };
                }
                if (nodeGlobalDofIds[1] > -1)
                {
                    M[nodeGlobalDofIds[1]] = { nodeData.m_YR, nodeData.m_YI };
                }
                if (nodeGlobalDofIds[2] > -1)
                {
                    M[nodeGlobalDofIds[2]] = { nodeData.m_ZR, nodeData.m_ZI };
                }
                if (nodeGlobalDofIds[3] > -1)
                {
                    M[nodeGlobalDofIds[3]] = { nodeData.m_RXR, nodeData.m_RXI };
                }
                if (nodeGlobalDofIds[4] > -1)
                {
                    M[nodeGlobalDofIds[4]] = { nodeData.m_RYR, nodeData.m_RYI };
                }
                if (nodeGlobalDofIds[5] > -1)
                {
                    M[nodeGlobalDofIds[5]] = { nodeData.m_RZR, nodeData.m_RZI };
                }
            }
        }
    };

};  // end namespace FEMSolver
SG_NAMESPACE_CLOSE